home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / util / boot / BlizKick.lha / BlizKick / bkapi.lha / bkapi / bkapi.c next >
C/C++ Source or Header  |  2000-03-06  |  22KB  |  889 lines

  1. /* BlizKick EXTRES allocation API functions.
  2.  
  3.    Written by Harry "Piru" Sintonen, Jan 2000.
  4.    Public Domain.
  5.  
  6. */
  7.  
  8. #include "bkapi.h"
  9.  
  10. #define __USE_SYSBASE 1
  11.  
  12. #include <proto/exec.h>
  13. #include <proto/dos.h>
  14.  
  15.  
  16. /****** bkapi.o/--background-- ***********************************************
  17. *
  18. *   PURPOSE
  19. *    If you don't know what BlizKick is get util/boot/BlizKick.lha
  20. *    from aminet and read the documentation of it.
  21. *
  22. *    The BlizKick EXTRES buffer is a finite space where BlizKick stores
  23. *    resident tags. This area is magically added to Kickstart ROM's
  24. *    internal list of memory areas to scan for resident tags. As a
  25. *    result BlizKick does not need to use unreliable exec.library
  26. *    KickMem & KickPtr vectors.
  27. *
  28. *    This package provides easy (as easy as it can get) access to this
  29. *    BlizKick EXTRES buffer.
  30. *
  31. *    First application to think of, would be ROM Update software that
  32. *    could easily kick in new resident module by just calling
  33. *    er_allocmem and copying resident tag to memory area returned. On
  34. *    next reboot this new resident tag would be activated.
  35. *
  36. *    To get things even easier, one can use InternalLoadSeg with
  37. *    er_allocmem as allocfunc, er_free as freefunc and dos Read() as
  38. *    readfunc. Then just LoadSeg any library / device to make it
  39. *    resident. Relocs and such get handled autogically! (however most
  40. *    disk based libraries would not survive, namely residenttag ln_Pri
  41. *    is wrong.)
  42. *
  43. *    Don't expect this API to stay unchanged. There will be some sort
  44. *    of MMU protection for EXTRES buffer some day... I think. However
  45. *    programs respecting ERH_API_V1 will probably recompile out of the
  46. *    box in the future too.
  47. *
  48. *   HISTORY
  49. *    1.0.1 - 17th Jan 2000, second release. fixed a typo.
  50. *    1.0.0 - 15th Jan 2000, first release.
  51. *
  52. *   LEGAL
  53. *    Written by Harry "Piru" Sintonen, Jan 2000.
  54. *    bkapi package is public domain.
  55. *
  56. ******************************************************************************
  57. *
  58. */
  59.  
  60. struct bkerhss *glob_ss = NULL;
  61.  
  62.  
  63. /*#define BKDEBUG*/
  64.  
  65. #ifdef BKDEBUG
  66. #  define D(a) (a);
  67. #else
  68. #  define D(a) ;
  69. #endif
  70.  
  71.  
  72. /****** bkapi.o/er_init ******************************************************
  73. *
  74. *   NAME
  75. *    er_init -- initialize EXTRES buffer use
  76. *
  77. *   SYNOPSIS
  78. *    version = er_init()
  79. *    D0
  80. *
  81. *    ULONG er_init();
  82. *
  83. *   FUNCTION
  84. *    Initializes use of EXTRES buffer memory pool of BlizKick. This
  85. *    routine must be called before using any of the other functions.
  86. *
  87. *   RESULT
  88. *    version - version number of EXTRES buf API available or zero
  89. *        if EXTRES buf could not be found (ie. BlizKick not run).
  90. *        Currently ERH_API_V1.
  91. *
  92. *   SEE ALSO
  93. *
  94. ******************************************************************************
  95. *
  96. */
  97.  
  98. ULONG er_init(void) {
  99.   struct bkerhss *ss;
  100.  
  101.   if (!glob_ss) {
  102.  
  103.     Forbid();
  104.     ss = (struct bkerhss *) FindSemaphore("EXTRES Handler");
  105.     Permit();
  106.  
  107.     if (ss) {
  108.  
  109.       switch (ss->version) {
  110.  
  111.         case ERH_API_V1:
  112.           glob_ss = ss;
  113.           break;
  114.  
  115.         /*
  116.         case ERH_API_V2:
  117.           glob_ss = ss;
  118.           ... could do some version dependant check / init here ...
  119.           break;
  120.         */
  121.       }
  122.  
  123.       /* force sanity check */
  124.       er_availmem(MEMF_LARGEST);
  125.  
  126.     }
  127.   }
  128.   return glob_ss ? glob_ss->version : 0;
  129. }
  130.  
  131.  
  132. /****** bkapi.o/er_alloc *****************************************************
  133. *
  134. *   NAME
  135. *    er_alloc -- allocate bytesize bytes from EXTRES memory pool
  136. *
  137. *   SYNOPSIS
  138. *    memoryblock = er_alloc(bytesize)
  139. *    D0               D0
  140. *
  141. *    void *er_alloc(ULONG);
  142. *
  143. *   FUNCTION
  144. *    Allocates memory from EXTRES buffer memory pool of BlizKick. This
  145. *    memory area is specific in a way that resident tags will be scanned
  146. *    from this area on system boot up.
  147. *
  148. *    This means easy addition of system transparent resident tags.
  149. *    System transparent means no kickmem or kicktag pointers will be
  150. *    used.
  151. *
  152. *   INPUTS
  153. *    bytesize - the size of the desired block in bytes.  (will
  154. *        automatically round this number to a multiple of the
  155. *        system memory chunk size)
  156. *
  157. *   RESULT
  158. *    memoryblock - a pointer to the newly allocated memory block.
  159. *        If there are no free memory regions large enough to satisfy
  160. *        the request, zero will be returned.  The pointer must be
  161. *        The memory block returned is quad word aligned.
  162. *
  163. *   WARNING
  164. *    The result of any memory allocation MUST be checked, and a viable
  165. *    error handling path taken. ANY allocation may fail if memory has
  166. *    been filled.
  167. *
  168. *   NOTE
  169. *    Allocation *will* fail if BlizKick is not run.
  170. *
  171. *   SEE ALSO
  172. *    er_allocmem, er_free, exec.library/Allocate
  173. *
  174. ******************************************************************************
  175. *
  176. */
  177.  
  178. void * ASM er_alloc(REG(d0,ULONG bytesize)) {
  179.   void *ret = NULL;
  180.  
  181.   if (glob_ss) {
  182.  
  183.     ObtainSemaphore(&glob_ss->ss);
  184.     ret = Allocate(glob_ss->mh, bytesize);
  185.     ReleaseSemaphore(&glob_ss->ss);
  186.   }
  187.  
  188.   if (!ret) SetIoErr(ERROR_NO_FREE_STORE);
  189.   return ret;
  190. }
  191.  
  192.  
  193. /****** bkapi.o/er_allocmem **************************************************
  194. *
  195. *   NAME
  196. *    er_allocmem -- AllocMem wrapper for er_alloc
  197. *
  198. *   SYNOPSIS
  199. *    memoryblock = er_allocmem(bytesize, attributes)
  200. *    D0              D0        D1
  201. *
  202. *    void *er_allocmem(ULONG, ULONG);
  203. *
  204. *   FUNCTION
  205. *    Allocates memory from EXTRES buffer memory pool of BlizKick. This
  206. *    memory area is specific in a way that resident tags will be scanned
  207. *    from this area on system boot up.
  208. *
  209. *    This means easy addition of system transparent resident tags.
  210. *    System transparent means no kickmem or kicktag pointers will be
  211. *    used.
  212. *
  213. *    This function is quite similar to er_alloc, the only difference
  214. *    is that er_allocmem supports MEMF_CLEAR.
  215. *
  216. *    If MEMF_CHIP is specified this function will fail.
  217. *
  218. *   INPUTS
  219. *    bytesize - the size of the desired block in bytes.  (will
  220. *        automatically round this number to a multiple of the
  221. *        system memory chunk size)
  222. *
  223. *    attributes -
  224. *        requirements
  225. *
  226. *        MEMF_CHIP:    Will cause the allocation to fail. EXTRES
  227. *                buffer memory is in fastmem.
  228. *
  229. *        options
  230. *
  231. *        MEMF_CLEAR:    The memory will be initialized to all
  232. *                zeros.
  233. *
  234. *   RESULT
  235. *    memoryBlock - a pointer to the newly allocated memory block.
  236. *        If there are no free memory regions large enough to satisfy
  237. *        the request, zero will be returned. The pointer must be
  238. *        checked for zero before the memory block may be used!
  239. *        The memory block returned is quad word aligned.
  240. *
  241. *   WARNING
  242. *    The result of any memory allocation MUST be checked, and a viable
  243. *    error handling path taken. ANY allocation may fail if memory has
  244. *    been filled.
  245. *
  246. *   NOTE
  247. *    Allocation *will* fail if BlizKick is not run.
  248. *
  249. *    MEMF_CLEAR is the only flag supported! Other flags will be
  250. *    silentry ignored, except MEMF_CHIP that will cause allocation to
  251. *    fail.
  252. *
  253. *    This function is provided for completeness and also for use as
  254. *    dos.library/InternalLoadSeg() allocfunc.
  255. *
  256. *   SEE ALSO
  257. *    er_alloc, er_free, exec.library/AllocMem, exec/memory.h
  258. *
  259. ******************************************************************************
  260. *
  261. */
  262.  
  263. void * __saveds ASM er_allocmem(REG(d0,ULONG bytesize), REG(d1,ULONG attributes)) {
  264.   void *ret = NULL;
  265.   ULONG *clearptr;
  266.   
  267.   if ( (bytesize==0) || (attributes & MEMF_CHIP) ) return NULL;
  268.  
  269.   if (glob_ss) {
  270.  
  271.     ObtainSemaphore(&glob_ss->ss);
  272.  
  273.     if ( (ret = Allocate(glob_ss->mh, bytesize)) ) {
  274.  
  275.       D(Printf("er_allocmem(%ld) = $%lx\n",
  276.                bytesize,(ULONG) ret));
  277.  
  278.       /* actually the following could clear a bit too much, but it
  279.          doesn't really matter. should clear only bytesize bytes. */
  280.  
  281.       if (attributes & MEMF_CLEAR) {
  282.         clearptr = (ULONG *) ret;
  283.         bytesize = (bytesize + MEM_BLOCKMASK) & -MEM_BLOCKSIZE;
  284.  
  285.         D(Printf("er_allocmem: clearing %ld bytes from $%lx\n",
  286.                  bytesize,(ULONG) clearptr));
  287.  
  288.         for ( ; bytesize; bytesize -= 8) {
  289.           *clearptr++ = 0;
  290.           *clearptr++ = 0;
  291.         }
  292.       }
  293.     }
  294.  
  295.     ReleaseSemaphore(&glob_ss->ss);
  296.   }
  297.  
  298.   if (!ret) SetIoErr(ERROR_NO_FREE_STORE);
  299.  
  300.   return ret;
  301. }
  302.  
  303.  
  304. /****** bkapi.o/er_free ******************************************************
  305. *
  306. *   NAME
  307. *    er_free -- deallocate memory from EXTRES memory pool
  308. *
  309. *   SYNOPSIS
  310. *    er_free(memoryblock, bytesize)
  311. *        A1         D0
  312. *
  313. *    void er_free(void *, ULONG);
  314. *
  315. *   FUNCTION
  316. *    Erase and free a region of memory, returning it to the EXTRES
  317. *    memory pool.
  318. *
  319. *   INPUTS
  320. *    memoryblock - pointer to the memory block to free
  321. *    bytesize - the size of the desired block in bytes. (will
  322. *        automatically round this number to a multiple of the
  323. *        system memory chunk size)
  324. *
  325. *   NOTE
  326. *    If a block of memory is freed twice, the system will Guru. The
  327. *    Alert is AN_FreeTwice ($01000009). If you pass the wrong pointer,
  328. *    you will probably see AN_MemCorrupt $01000005.
  329. *
  330. *    Will also fill the memory area to be released with all ones
  331. *    before releasing. This ensures no partial resident tag will
  332. *    remain in unallocated memory.
  333. *
  334. *    Both memory allocated by er_alloc and er_allocmem must be released
  335. *    with this function!
  336. *
  337. *   SEE ALSO
  338. *    er_alloc, er_allocmem, exec.library/Allocate
  339. *
  340. ******************************************************************************
  341. *
  342. */
  343.  
  344. void __saveds ASM er_free(REG(a1,void *memblock), REG(d0,ULONG bytesize)) {
  345.   ULONG *fillptr; ULONG fillsize;
  346.  
  347.   if ( (bytesize==NULL) || (memblock==NULL) ) return;
  348.  
  349.   if (glob_ss) {
  350.  
  351.     /* actually the following could fill a bit too much, but it
  352.        doesn't really matter. should fill only bytesize bytes. */
  353.  
  354.     fillptr = (ULONG *) ((ULONG)memblock & -MEM_BLOCKSIZE);
  355.     fillsize = (bytesize + MEM_BLOCKMASK +
  356.                ((ULONG) fillptr - (ULONG) memblock)) &
  357.                -MEM_BLOCKSIZE;
  358.  
  359.     /* some sanity checking - note that doesn't require ObtainSemaphore
  360.        because only mh_Lower and mh_Upper are read (both are static) */
  361.  
  362.     if ( ((ULONG) fillptr < (ULONG) glob_ss->mh->mh_Lower) ||
  363.          (((ULONG)fillptr + fillsize) > (ULONG) glob_ss->mh->mh_Upper) ) {
  364.  
  365.        D(Printf("er_free: *** illegal arguments ***!\n"));
  366.        return;
  367.     }
  368.  
  369.     D(Printf("er_free, memblock: $%lx bytesize: %ld fillptr: $%lx fillsize: %ld\n",
  370.              (ULONG) memblock, bytesize, (ULONG) fillptr, fillsize));
  371.  
  372.     ObtainSemaphore(&glob_ss->ss);
  373.  
  374.     for ( ; fillsize; fillsize -= 8) {
  375.       *fillptr++ = 0xffffffff;
  376.       *fillptr++ = 0xffffffff;
  377.     }
  378.  
  379.     Deallocate(glob_ss->mh, memblock, bytesize);
  380.     ReleaseSemaphore(&glob_ss->ss);
  381.  
  382.   }
  383. }
  384.  
  385.  
  386. /****** bkapi.o/er_allocvec **************************************************
  387. *
  388. *   NAME
  389. *    er_allocvec -- allocate EXTRES memory and keep track of the size
  390. *
  391. *   SYNOPSIS
  392. *    memoryblock = er_allocvec(bytesize, attributes)
  393. *    D0              D0        D1
  394. *
  395. *    void *er_allocvec(ULONG, ULONG);
  396. *
  397. *   FUNCTION
  398. *    This function works similar to er_allocmem(), but tracks the size
  399. *    of the allocation.
  400. *
  401. *    See the er_allocmem() documentation for details.
  402. *
  403. *   RESULT
  404. *    memoryBlock - a pointer to the newly allocated memory block.
  405. *        If there are no free memory regions large enough to satisfy
  406. *        the request, zero will be returned. The pointer must be
  407. *        checked for zero before the memory block may be used!
  408. *        The memory block returned is *long* word aligned.
  409. *
  410. *   WARNING
  411. *    The result of any memory allocation MUST be checked, and a viable
  412. *    error handling path taken. ANY allocation may fail if memory has
  413. *    been filled.
  414. *
  415. *   SEE ALSO
  416. *    er_allocmem, er_freevec, exec.library/AllocVec
  417. *
  418. ******************************************************************************
  419. *
  420. */
  421.  
  422. void * ASM er_allocvec(REG(d0,ULONG bytesize), REG(d1,ULONG attributes)) {
  423.   void *ret;
  424.  
  425.   bytesize += 4;
  426.   if ( (ret = er_allocmem(bytesize, attributes)) ) {
  427.     *(ULONG *)ret = bytesize;
  428.     return (void *) ((ULONG) ret + 4);
  429.   }
  430.  
  431.   return NULL;
  432. }
  433.  
  434.  
  435. /****** bkapi.o/er_freevec ***************************************************
  436. *
  437. *   NAME
  438. *    er_freevec -- free er_allocvec() EXTRES memory
  439. *
  440. *   SYNOPSIS
  441. *    er_freevec(memoryblock)
  442. *           A1
  443. *
  444. *    void er_freevec(void *);
  445. *
  446. *   FUNCTION
  447. *    Free an allocation made by the er_allocvec() call.
  448. *
  449. *   NOTE
  450. *    If a block of memory is freed twice, the system will Guru. The
  451. *    Alert is AN_FreeTwice ($01000009). If you pass the wrong pointer,
  452. *    you will probably see AN_MemCorrupt $01000005.
  453. *
  454. *   INPUTS
  455. *    memoryblock - pointer to the memory block to free, or NULL.
  456. *
  457. *   SEE ALSO
  458. *    er_allocvec, exec.library/FreeVec
  459. *
  460. ******************************************************************************
  461. *
  462. */
  463.  
  464. void ASM er_freevec(REG(a1,void *memoryblock)) {
  465.   ULONG size;
  466.   if (memoryblock) {
  467.     memoryblock = (void *) ((ULONG) memoryblock - 4);
  468.     size = *((ULONG *) memoryblock);
  469.     er_free( memoryblock, size);
  470.   }
  471. }
  472.  
  473.  
  474. /****** bkapi.o/er_lock ******************************************************
  475. *
  476. *   NAME
  477. *    er_lock -- lock EXTRES buffer memory
  478. *
  479. *   SYNOPSIS
  480. *    er_lock()
  481. *
  482. *    void er_lock(void);
  483. *
  484. *   FUNCTION
  485. *    Locks access to EXTRES buffer memory for this task only.
  486. *
  487. *   WARNING
  488. *    Be *very* careful not to keep the lock if another process you
  489. *    depend/wait will try to er_lock() simultanously!
  490. *
  491. *   NOTE
  492. *    You *must* er_lock() before you read/write EXTRES buffer memory
  493. *    area. Call er_unlock() when done tempering with it.
  494. *
  495. *    er_lock() and er_unlock() nest.
  496. *
  497. *   SEE ALSO
  498. *    er_unlock, er_getarea
  499. *
  500. ******************************************************************************
  501. *
  502. */
  503.  
  504. void ASM er_lock(void) {
  505.   if (glob_ss) {
  506.  
  507.     ObtainSemaphore(&glob_ss->ss);
  508.  
  509.   }
  510. }
  511.  
  512.  
  513. /****** bkapi.o/er_unlock ****************************************************
  514. *
  515. *   NAME
  516. *    er_unlock -- unlock EXTRES buffer memory
  517. *
  518. *   SYNOPSIS
  519. *    er_unlock()
  520. *
  521. *    void er_unlock(void);
  522. *
  523. *   FUNCTION
  524. *    Unlock access to EXTRES buffer memory. Other tasks may bid for
  525. *    access now.
  526. *
  527. *   WARNING
  528. *    Be *very* careful not to keep the lock if another process you
  529. *    depend/wait will try to er_lock() simultanously!
  530. *
  531. *   NOTE
  532. *    You *must* er_lock() before you read/write EXTRES buffer memory
  533. *    area. Call er_unlock() when done tempering with it.
  534. *
  535. *    er_lock() and er_unlock() nest.
  536. *
  537. *   SEE ALSO
  538. *    er_lock, er_getarea
  539. *
  540. ******************************************************************************
  541. *
  542. */
  543.  
  544. void ASM er_unlock(void) {
  545.   if (glob_ss) {
  546.  
  547.     ReleaseSemaphore(&glob_ss->ss);
  548.  
  549.   }
  550. }
  551.  
  552.  
  553. /****** bkapi.o/er_getarea ***************************************************
  554. *
  555. *   NAME
  556. *    er_getarea -- get EXTRES resident module area
  557. *
  558. *   SYNOPSIS
  559. *    start = er_getarea(len_ptr)
  560. *    D0           A0
  561. *
  562. *    void *er_getarea(ULONG *);
  563. *
  564. *   FUNCTION
  565. *    Return lower and upper bound of memory area covered by EXTRES
  566. *    buffer.
  567. *
  568. *   INPUTS
  569. *    len_ptr - pointer to ULONG to put area lenght to.
  570. *
  571. *   RESULT
  572. *    start - pointer to start of resident module area. If there's no
  573. *        BlizKick EXTRES buffer available will be zero.
  574. *
  575. *   NOTE
  576. *    You *must* er_lock() before you read/write EXTRES buffer memory
  577. *    area. Call er_unlock() when done tempering with it.
  578. *
  579. *    Will return zero if BlizKick is not run.
  580. *
  581. *   SEE ALSO
  582. *    er_lock, er_unlock
  583. *
  584. ******************************************************************************
  585. *
  586. */
  587.  
  588. ULONG ASM er_getarea(REG(a0,ULONG *len_ptr)) {
  589.   ULONG ret = NULL;
  590.  
  591.   if (glob_ss) {
  592.     ObtainSemaphore(&glob_ss->ss);
  593.  
  594.     ret = (ULONG) glob_ss->mh->mh_Lower;
  595.     *len_ptr = (ULONG) glob_ss->mh->mh_Upper - ret;
  596.  
  597.     ReleaseSemaphore(&glob_ss->ss);
  598.   }
  599.   return ret;
  600. }
  601.  
  602.  
  603. /****** bkapi.o/er_availmem **************************************************
  604. *
  605. *   NAME
  606. *    er_availmem -- return EXTRES buffer memory available
  607. *
  608. *   SYNOPSIS
  609. *    size = er_availmem(requirements)
  610. *    D0           D1
  611. *
  612. *    ULONG er_availmem(ULONG);
  613. *
  614. *   FUNCTION
  615. *    This function returns the amount of free EXTRES buffer memory.
  616. *
  617. *    To find out what the largest block is, specify MEMF_LARGEST in
  618. *    attributes argument.
  619. *
  620. *   WARNING
  621. *    Due to the effect of multitasking, the value returned may not
  622. *    actually be the amount of free memory available at that instant.
  623. *    However if you have locked memory with er_lock() before, the
  624. *    result is exact.
  625. *
  626. *   INPUTS
  627. *    requirements - MEMF_LARGEST results calculation of the size of
  628. *        the largest block.
  629. *
  630. *   RESULT
  631. *    size - total free space remaining (or the largest free block).
  632. *
  633. *   NOTE
  634. *    er_availmem(MEMF_LARGEST) does a consistency check on the
  635. *    memory list. In case of an error 0xFFFFFFFF is returned, and
  636. *    further allocations are impossible. If memory header itself is
  637. *    bad will alert with BKA_MemoryInsane.
  638. *
  639. *   SEE ALSO
  640. *    exec.library/AvailMem, exec/memory.h
  641. *
  642. ******************************************************************************
  643. *
  644. */
  645.  
  646. ULONG ASM er_availmem(REG(d1,ULONG attributes)) {
  647.   struct MemHeader *mh;
  648.   struct MemChunk *mc, *predmc;
  649.   ULONG ret = NULL, free = 0, failed = 0;
  650.  
  651.   if (glob_ss) {
  652.     ObtainSemaphore(&glob_ss->ss);
  653.  
  654.     if (attributes & MEMF_LARGEST) {
  655.  
  656.       mh = glob_ss->mh;
  657.  
  658.       if ( (mh->mh_Node.ln_Succ == NULL) &&
  659.            (mh->mh_Node.ln_Pred == NULL) &&
  660.            (mh->mh_Node.ln_Type == NT_MEMORY) &&
  661.            (((ULONG) mh->mh_Lower & MEM_BLOCKMASK) == 0) &&
  662.            (((ULONG) mh->mh_Upper & MEM_BLOCKMASK) == 0) &&
  663.            (mh->mh_Lower < mh->mh_Upper)
  664.          ) {
  665.  
  666.         mc = mh->mh_First;
  667.         predmc = (struct MemChunk *) ((ULONG) mc - 1);
  668.  
  669.         while (mc && (!failed) ) {
  670.           if ( ( ((ULONG) mc & MEM_BLOCKMASK) == 0) &&
  671.                ((ULONG) mc > (ULONG) predmc) &&
  672.                ((ULONG) mc <= ((ULONG) mh->mh_Upper - MEM_BLOCKSIZE))
  673.              ) {
  674.  
  675.             if ( (mc->mc_Bytes & MEM_BLOCKMASK) == 0) {
  676.  
  677.               free += mc->mc_Bytes;
  678.               if (mc->mc_Bytes > ret) ret = mc->mc_Bytes;
  679.  
  680.             } else failed = 1;
  681.  
  682.             predmc = mc;
  683.             mc = mc->mc_Next;
  684.  
  685.           } else failed = 1;
  686.  
  687.         }
  688.       } else {
  689.         failed = 2;
  690.       }
  691.  
  692.       if ( (!failed) && (free != mh->mh_Free) ) failed = 1;
  693.  
  694.       switch (failed) {
  695.         case 2:
  696.           /* memheader screwed up!! */
  697.           D(Printf("er_availmem(largest): *** memheader fucked ***!!\n"));
  698.           Alert(BKA_MemoryInsane);
  699.           /* fall thru */
  700.         case 1:
  701.           D(Printf("er_availmem(largest): freelist fucked!\n"));
  702.           mh->mh_First = NULL;
  703.           mh->mh_Free = 0;
  704.           ret = 0xFFFFFFFF;
  705.           break;
  706.       }
  707.  
  708.     } else {
  709.       ret = glob_ss->mh->mh_Free;
  710.     }
  711.  
  712.     ReleaseSemaphore(&glob_ss->ss);
  713.   }
  714.   return ret;
  715. }
  716.  
  717. /****** bkapi.o/er_nextresident **********************************************
  718. *
  719. *   NAME
  720. *    er_nextresident -- find first/next resident tag from EXTRES buffer
  721. *
  722. *   SYNOPSIS
  723. *    nextresident = er_nextresident(oldresident)
  724. *    D0                   A0
  725. *
  726. *    struct Resident *er_nextresident(struct Resident *);
  727. *
  728. *   FUNCTION
  729. *    Find first or next Resident tag from EXTRES buffer memory.
  730. *
  731. *   WARNING
  732. *    You *must* have er_lock() on memory before calling this routine!
  733. *    Keep the lock until you're done accessing the resident tag(s).
  734. *
  735. *   INPUTS
  736. *    oldresident - startpoint for search, will not find this
  737. *        particular resident but next. Pass NULL to find first
  738. *        resident.
  739. *
  740. *   RESULT
  741. *    nextresident - pointer to resident tag structure or zero if no
  742. *        more resident tags could be found.
  743. *
  744. *   EXAMPLE
  745. *
  746. *    struct Resident *res = NULL;
  747. *
  748. *    er_lock();
  749. *    while ( (res = er_nextresident(res)) ) {
  750. *      \* do something with this Resident tag *\
  751. *    }
  752. *    er_unlock();
  753. *
  754. *   SEE ALSO
  755. *    er_findresident
  756. *
  757. ******************************************************************************
  758. *
  759. */
  760.  
  761. struct Resident * ASM er_nextresident(REG(a0,struct Resident *oldresident)) {
  762.   UWORD *wpt;
  763.   LONG numw;
  764.  
  765.   if (glob_ss) {
  766.  
  767.     if (oldresident) {
  768.  
  769.       /* sanitycheck input */
  770.  
  771.       if ( ((ULONG) oldresident < (ULONG) glob_ss->mh->mh_Lower) ||
  772.            (((ULONG) oldresident + sizeof(struct Resident)) >=
  773.            (ULONG) glob_ss->mh->mh_Upper) ) {
  774.          return NULL;
  775.       }
  776.  
  777.       if ( (oldresident->rt_MatchWord == RTC_MATCHWORD) &&
  778.            (oldresident->rt_MatchTag == oldresident) ) {
  779.  
  780.         wpt = (UWORD *) oldresident->rt_EndSkip;
  781.  
  782.       } else {
  783.  
  784.         wpt = (UWORD *) (((ULONG) oldresident + 3) & -2);
  785.  
  786.       }
  787.  
  788.     } else {
  789.       wpt = (UWORD *) glob_ss->mh->mh_Lower;
  790.     }
  791.  
  792.     /* more sanity checking */
  793.  
  794.     if ( ((ULONG) wpt < (ULONG) glob_ss->mh->mh_Lower) ||
  795.          (((ULONG) wpt + sizeof(struct Resident)) >=
  796.          (ULONG) glob_ss->mh->mh_Upper) ) {
  797.        return NULL;
  798.     }
  799.  
  800.     numw = (((ULONG) glob_ss->mh->mh_Upper
  801.              - sizeof(struct Resident)
  802.              - (ULONG) wpt) ) >> 1;
  803.  
  804.     if (numw > 0) {
  805.       for ( ; ; ) {
  806.         while (--numw && (*wpt++ != RTC_MATCHWORD));
  807.         if (!numw) return NULL;
  808.         if ( *(ULONG *) wpt == ((ULONG) wpt - 2) ) {
  809.           return (struct Resident *) ((ULONG) wpt - 2);
  810.         }
  811.       }
  812.     }
  813.   }
  814.  
  815.   return NULL;
  816. }
  817.  
  818.  
  819. /****** bkapi.o/er_findresident **********************************************
  820. *
  821. *   NAME
  822. *    er_findresident -- find resident tag from EXTRES buffer by name
  823. *
  824. *   SYNOPSIS
  825. *    resident = er_findresident(name)
  826. *    D0               A1
  827. *
  828. *    struct Resident *er_findresident(STRPTR);
  829. *
  830. *   FUNCTION
  831. *    Scan EXTRES buffer memory for Resident tag with given name.
  832. *
  833. *   WARNING
  834. *    You must have er_lock() on memory before calling this routine
  835. *    if you intend to access the resident tag found! Keep the lock
  836. *    until you're done accessing the Resident tag.
  837. *
  838. *   INPUTS
  839. *    name - pointer to name string
  840. *
  841. *   RESULT
  842. *    resident - pointer to the resident tag structure or
  843. *        zero if none found.
  844. *
  845. *   EXAMPLE
  846. *
  847. *    struct Resident *res = NULL;
  848. *
  849. *    er_lock();
  850. *    if (res = er_findresident("EXTRES Handler")) {
  851. *      \* do something with the resident *\
  852. *
  853. *      \* keep the lock until done! *\
  854. *    }
  855. *    er_unlock();
  856. *
  857. *   NOTE
  858. *    exec.library/FindResident() will only find the currently *active*
  859. *    resident tags in EXTRES buffer memory. Also if resident tag with
  860. *    same name is found from both the ROM and EXTRES memory, the one
  861. *    having newer rt_Version will be activated on boot, and thus
  862. *    exec.library/FindResident() will find that particular resident.
  863. *
  864. *   SEE ALSO
  865. *    er_nextresident, exec.library/FindResident, exec/resident.h
  866. *
  867. ******************************************************************************
  868. *
  869. */
  870.  
  871. struct Resident * ASM er_findresident(REG(a1,STRPTR name)) {
  872.   struct Resident *ret = NULL;
  873.   STRPTR s1, s2;
  874.  
  875.   if (glob_ss) {
  876.     er_lock();
  877.     while ( (ret = er_nextresident(ret)) ) {
  878.       for ( s1 = name, s2 = ret->rt_Name; *s1 && (*s1 == *s2) ; s1++, s2++ );
  879.       if (*s1 == *s2) {
  880.         er_unlock();
  881.         return ret;
  882.       }
  883.     }
  884.     er_unlock();
  885.   }
  886.  
  887.   return NULL;
  888. }
  889.